Day 13

Problem
Code

I don't really have a title for this one, or much to say about part 1 in general.

fn reflection_score(map: &[&[u8]]) -> usize {
    // Find reflection around a vertical line.
    'outer: for x in 1..map[0].len() {
        let dx = usize::min(x, map[0].len() - x);
        for dx in 1..=dx {
            for row in map {
                if row[x - dx] != row[x + dx - 1] {
                    continue 'outer;
                }
            }
        }
        return x;
    }

    // Find reflection around a horizontal line.
    'outer: for y in 1..map.len() {
        let dy = usize::min(y, map.len() - y);
        for dy in 1..=dy {
            for x in 0..map[0].len() {
                if map[y - dy][x] != map[y + dy - 1][x] {
                    continue 'outer;
                }
            }
        }
        return y * 100;
    }

    0
}

It's just about implementing the thing. My version is honestly kind of fiddly, but it works. I'm glad Rust has labelled loops, so I can continue the 'outer one.

Part 2 was really funny though. When you first read it, it sounds like you now need to like, idk. Try your part 1 code on every changed version of every map. But that sounds unreasonable.

No, all part 2 is saying is that the line we're looking for has to have one mistake in its reflection. So simply... keep track of whether there was a mistake!

fn smudged_reflection_score(map: &[&[u8]]) -> usize {
    // Find reflection around a vertical line.
    'outer: for x in 1..map[0].len() {
        let mut mistake = false;
        let dx = usize::min(x, map[0].len() - x);
        for dx in 1..=dx {
            for row in map {
                if row[x - dx] != row[x + dx - 1] {
                    match mistake {
                        true => continue 'outer,
                        false => mistake = true,
                    }
                }
            }
        }
        if mistake {
            return x;
        }
    }

    // Find reflection around a horizontal line.
    'outer: for y in 1..map.len() {
        let mut mistake = false;
        let dy = usize::min(y, map.len() - y);
        for dy in 1..=dy {
            for x in 0..map[0].len() {
                if map[y - dy][x] != map[y + dy - 1][x] {
                    match mistake {
                        true => continue 'outer,
                        false => mistake = true,
                    }
                }
            }
        }
        if mistake {
            return y * 100;
        }
    }

    0
}

Straightforward modification of part 1. When we run into a mistake, just remember it; unless there was already one, in which case, nope out like before. Only return a score if mistake is true, to avoid accidentally finding the part 1 reflection line again (part 2 is explicit that we want a different one).

Also, ignore the fact that I match bool instead of if/else. When both branches are one-liners, it looks neater to me.

Anyway, in the spirit of golfing a bit, I then combined both versions into one function:

fn reflection_score(map: &[&[u8]], smudged: bool) -> usize {
    // Find reflection around a vertical line.
    'outer: for x in 1..map[0].len() {
        let mut mistake = !smudged;
        let dx = usize::min(x, map[0].len() - x);
        for dx in 1..=dx {
            for row in map {
                if row[x - dx] != row[x + dx - 1] {
                    match mistake {
                        true => continue 'outer,
                        false => mistake = true,
                    }
                }
            }
        }
        if mistake {
            return x;
        }
    }

    // Find reflection around a horizontal line.
    'outer: for y in 1..map.len() {
        let mut mistake = !smudged;
        let dy = usize::min(y, map.len() - y);
        for dy in 1..=dy {
            for x in 0..map[0].len() {
                if map[y - dy][x] != map[y + dy - 1][x] {
                    match mistake {
                        true => continue 'outer,
                        false => mistake = true,
                    }
                }
            }
        }
        if mistake {
            return y * 100;
        }
    }

    0
}

Just take the code from part 2, but, in part 1 mode, act as if we've already seen a mistake.

Pretty neat problem today, I think. And, other than the actual gnarly reflection finding, pretty neat solution from me, too.